package com.travelsmart.client.apresentacao.mvc;

import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.travelsmart.client.apresentacao.controller.AbstractCommandController;
import com.travelsmart.client.apresentacao.controller.CommandController;
import com.travelsmart.client.apresentacao.controller.Observer;
import com.travelsmart.client.apresentacao.controller.TravelSmartCommandController;
import com.travelsmart.client.apresentacao.i18n.I18nMessages;
import com.travelsmart.client.apresentacao.image.ImagesResource;
import com.travelsmart.client.apresentacao.model.SmartHotelModel;
import com.travelsmart.client.apresentacao.model.SmartHotelModel.LOAD_STATUS;
import com.travelsmart.client.apresentacao.screen.ConsultarReservasHotelScreen;
import com.travelsmart.client.apresentacao.screen.RealizarReservaHotelScreen;
import com.travelsmart.client.apresentacao.view.ViewCriaReservaHotel;
import com.travelsmart.client.apresentacao.view.ViewDadosHotel;
import com.travelsmart.client.apresentacao.view.ViewInfoReservaHotel;
import com.travelsmart.client.apresentacao.view.ViewListaHotel;
import com.travelsmart.client.apresentacao.view.ViewListaReservaHotel;
import com.travelsmart.client.apresentacao.view.ViewPesquisaHotel;
import com.travelsmart.client.apresentacao.widget.FormAdminDialog;
import com.travelsmart.client.apresentacao.widget.FormDialogBox;
import com.travelsmart.client.bean.to.FilterInfoHotel;
import com.travelsmart.client.bean.to.FilterPesquisaHotel;
import com.travelsmart.client.bean.to.HotelTO;
import com.travelsmart.client.bean.to.ParametroOrdenacao;
import com.travelsmart.client.bean.to.QuartoTO;
import com.travelsmart.client.bean.to.ReservaHotelTO;

/**
 * Classe que cria as Views e os controllers Configura a rela��o entre Model,
 * View e Controller 1 - Implementa��o (classes an�nimas) e cria��o ( new ) dos
 * controllers (TravelSmartController<????>) As classes controllers ficam
 * atreladas aos models. Desta forma, o controller poder� chamar m�todos do
 * model. 2 - Cria��o dos objetos views (views, screens e widgets ). O
 * controllers s�o passados nos construtores dos views, assim ficam atrelados a
 * eles. Qualquer a��o do usu�rio que for feita no view e que resulte em um
 * evento relevante e consistente p/ o model chamar� um m�todo handlerSucesso()
 * na classe controller; 3 - Registram-se os Views como ouvinte (observer) no
 * model. Qualquer altera��o nos dados do model provoca uma notifica��o a todos
 * os ouvintes registrados. Assim, uma notifica��o sempre ser� recebida pelo
 * view;
 * 
 * Model-View-Controller O padr�o de arquitetura MVC � uma combina��o de padr�es
 * centrada no padr�o Observer Consiste de tr�s participantes Model: representa
 * os dados da aplica��o e regras de neg�cio associadas com os dados. Notifica o
 * View sobre altera��es. View: � um Observer para o Model, ou seja, altera��es
 * no Model s�o notificadas p/ as views. Notifica o Controller sobre eventos
 * iniciados pelo usu�rio e l� dados do Model. Controller: � um Observer para o
 * View. Encapsula l�gica de controle que afeta o Model e seleciona View.
 * 
 * @author arthur
 * 
 */
public class MVCHotel {

	public static RealizarReservaHotelScreen criarRealizarReservaHotelScreen() {
		RealizarReservaHotelScreen screen = null;
		// # INICIO - EXERC. 3

		// Controles

		final CommandController<FilterPesquisaHotel> handlerPesquisarHotel = new TravelSmartCommandController<FilterPesquisaHotel>() {
			public void handle(final FilterPesquisaHotel filter) {
				SmartHotelModel.instance.getListaHotelModel()
						.pesquisaListHotel(filter);

			}

		};

		final CommandController<FilterPesquisaHotel> handlerAlterarFilterPesquisaHotel = new AbstractCommandController<FilterPesquisaHotel>() {
			public void handle(final FilterPesquisaHotel filter) {
				SmartHotelModel.instance.getFilterPesquisaHotelModel()
						.setFilterPesquisaHotel(filter);

			}

		};

		final CommandController<ParametroOrdenacao> handlerOrdenarLista = new TravelSmartCommandController<ParametroOrdenacao>() {
			public void handle(final ParametroOrdenacao param) {
				SmartHotelModel.instance.getListaHotelModel().ordenaListHotel(
						param);

			}

		};

		final CommandController<FilterInfoHotel> handlerObterDadosHotel = new TravelSmartCommandController<FilterInfoHotel>() {
			public void handle(FilterInfoHotel filterInfoHotel) {
				SmartHotelModel.instance.getHotelModel().obterDadosHotel(
						filterInfoHotel);

			}

		};

		final CommandController<QuartoTO> handlerSelecionarQuartoHotel = new AbstractCommandController<QuartoTO>() {
			public void handle(QuartoTO room) {
				SmartHotelModel.instance.getQuartoModel().setQuartoTO(room);

			}

		};

		final CommandController<ReservaHotelTO> handlerCriarReservaHotel = new TravelSmartCommandController<ReservaHotelTO>() {
			public void handle(ReservaHotelTO to) {
				SmartHotelModel.instance.getReservaModel().criarReserva(to);

			}

		};
		// FIM - EXERC. 3

		// # INICIO - EXERC. 3

		// Cria as views associando-as com os controles

		final ViewCriaReservaHotel viewReservaHotel = new ViewCriaReservaHotel(
				handlerCriarReservaHotel);
		final ViewDadosHotel viewDadosHotel = new ViewDadosHotel(
				handlerSelecionarQuartoHotel);
		final ViewListaHotel viewListaHotel = new ViewListaHotel(
				handlerObterDadosHotel, handlerOrdenarLista);
		final ViewPesquisaHotel viewPesquisaHotel = new ViewPesquisaHotel(
				handlerPesquisarHotel, handlerAlterarFilterPesquisaHotel,
				handlerAlterarFilterPesquisaHotel);

		screen = new RealizarReservaHotelScreen(viewPesquisaHotel,
				viewListaHotel, viewDadosHotel, viewReservaHotel);
		// FIM - EXERC. 3

		// # INICIO - EXERC. 3

		// Associa o model com as views

		// Associa viewListaHotel com os Models

		SmartHotelModel.instance.getListaHotelModel().addObserver(
				viewListaHotel);
		SmartHotelModel.instance.getFilterPesquisaHotelModel().addObserver(
				viewListaHotel.getViewInfoHotel());
		SmartHotelModel.instance.getFilterPesquisaHotelModel().addObserver(
				viewListaHotel.getViewTableHotel());
		SmartHotelModel.instance.getListaHotelModel().addObserver(
				viewListaHotel.getViewTableHotel());

		// # INICIO - EXERC. 4 //TODO Exercicio 4 
		SmartHotelModel.instance.getHotelModel().addObserver(
				new Observer<HotelTO>() {
					@Override
					public void update(HotelTO arg) {
						viewDadosHotel.getViewImagensHotel().exec(arg);
						viewDadosHotel.getViewInfoDetalhesHotel().exec(arg);
						viewDadosHotel.getViewListQuarto().exec(arg);
						viewDadosHotel.getViewMapHotel().exec(arg);
						viewDadosHotel.exec();
					}
				});
		// # FIM - EXERC. 4
		
		// Associa a viewReservaHotel com os models

		SmartHotelModel.instance.getHotelModel().addObserver(viewReservaHotel);
		SmartHotelModel.instance.getQuartoModel().addObserver(viewReservaHotel);
		SmartHotelModel.instance.getQuartoModel().addObserver(
				viewReservaHotel.getViewDadosRoom());
		SmartHotelModel.instance.getFilterPesquisaHotelModel().addObserver(
				viewReservaHotel);

		// Associa screen com os models

		SmartHotelModel.instance.getHotelModel().addObserver(screen);
		SmartHotelModel.instance.getQuartoModel().addObserver(screen);
		SmartHotelModel.instance.getListaHotelModel().addObserver(screen);
		SmartHotelModel.instance.getErroHotelModel().addObserver(screen);
		SmartHotelModel.instance.getMsgHotelModel().addObserver(screen);
		// FIM - EXERC. 3


		return screen;
	}

	public static void criarAdminViews() {
		SmartHotelModel.instance.getLoadModel().addObserver(
				new Observer<SmartHotelModel.LOAD_STATUS>() {
					FormAdminDialog adminDialog = new FormAdminDialog(
							I18nMessages.INSTANCE.carregando());

					@Override
					public void update(LOAD_STATUS arg) {
						if (arg.equals(LOAD_STATUS.LOADING)) {
							adminDialog.center();
						} else {
							adminDialog.hide();
						}
					}
				});

		SmartHotelModel.instance.getMsgHotelModel().addObserver(
				new Observer<String>() {

					@Override
					public void update(String arg) {
						new FormDialogBox(new Image(ImagesResource.INSTANCE
								.sucesso()), "Message", new HTML(arg)).show();
					}
				});
		SmartHotelModel.instance.getErroHotelModel().addObserver(
				new Observer<Throwable>() {

					@Override
					public void update(Throwable arg) {
						new FormDialogBox(new Image(ImagesResource.INSTANCE
								.falha()), "Erro", new HTML(arg.getMessage()))
								.show();
					}
				});

	}

	// # INICIO - EXERC. 1
	public static ConsultarReservasHotelScreen criarConsultarReservasHotelScreen() {
		TravelSmartCommandController<Integer> handlerNavegacaoPagina = new TravelSmartCommandController<Integer>() {

			@Override
			public void handle(Integer indexPagina) {
				SmartHotelModel.instance.getListaReservaModel().obterReservas(
						indexPagina);
			}
		};

		TravelSmartCommandController<Long> handlerSelecaoReserva = new TravelSmartCommandController<Long>() {

			@Override
			public void handle(Long idReservaSelecionada) {
				SmartHotelModel.instance.getReservaModel().obterReserva(
						idReservaSelecionada);
			}
		};

		final ViewListaReservaHotel viewListaReservaHotel = new ViewListaReservaHotel(
				handlerNavegacaoPagina, handlerSelecaoReserva);
		final ViewInfoReservaHotel viewInfoReservaHotel = new ViewInfoReservaHotel();
		ConsultarReservasHotelScreen screen = new ConsultarReservasHotelScreen(
				handlerNavegacaoPagina, viewListaReservaHotel,
				viewInfoReservaHotel);
		SmartHotelModel.instance.getListaReservaModel().addObserver(
				screen.getViewListaReservaHotel());
		SmartHotelModel.instance.getReservaModel().addObserver(
				viewInfoReservaHotel);
		SmartHotelModel.instance.getReservaModel().addObserver(screen);
		SmartHotelModel.instance.getListaReservaModel().addObserver(screen);

		return screen;
	}
	// FIM - EXERC. 1#

}
